#include "symtab.h"

#define TAILLE_DICO 50;

void creer_dico() {
  max = TAILLE_DICO;
  base = 0;
  sommet = 0;
  dico = malloc(max * sizeof(symbole));
}

void agrandir_dico()
{
  max *= 2;
  dico = realloc(dico, max * sizeof(symbole));
}

void add_variable(char *nom, bool isstatic)
{
  symbole *s = lookup_decl(nom);
  if(s == NULL)
    {
      if(sommet >= max)
		agrandir_dico();
      dico[sommet].nom = malloc(strlen(nom) + 1);
      strcpy(dico[sommet].nom, nom);
      dico[sommet].mtype = VARIABLE;

      int offset = -4 * (NB_LOCALES);
      char buf[10];
      sprintf(buf, "%d", offset);
      dico[sommet].content.var = malloc(sizeof(variable*));
      dico[sommet].var_adresse = concat(buf, "(%ebp)", NULL);
      sommet++;
    }
  else
    {
      char *message;
      switch(s->mtype)
	{
	case VARIABLE:	  
	  message = concat("Variable deja declaree : \"", nom, "\".\n", NULL);
	  yyerror(message);
	  break;
	case FONCTION:
	  message = concat("L'identifiant \"", nom, "\" existe deja, c'est une fonction.", "\n", NULL);
	  yyerror(message);
	  break;
	default:
	  message = concat("Bizarre, checker add_variable().\n", NULL);
	  yyerror(message);
	  break;
	}
      free(message);
    }
}
 
void add_array(char *nom, int size, bool isstatic)
{
  
}

void add_prototype(returntype rettype, char *nom, arguments *args)
{
  if(lookup_decl(nom) != NULL)
    {
      if(sommet >= max)
	agrandir_dico();
      dico[sommet].nom = malloc(strlen(nom) + 1);
      strcpy(dico[sommet].nom, nom);
      dico[sommet].mtype = FONCTION; 
      dico[sommet].func_rettype = rettype; 
      if(args != NULL)
	{
	  int nb_args = sizeof(args)/sizeof(arguments*);
	  dico[sommet].content.func = malloc(sizeof(function*));
	  dico[sommet].func_nb_args = nb_args;
	  int i;
	  for(i = 0; i < nb_args; i++)
	    dico[sommet].func_args[i].type = args[i].type;      
	  dico[sommet].func_visited = false;
	}
      else
	dico[sommet].func_nb_args = 0;
      sommet++;
    }
  else
    {
      char *message = concat("Fonction deja declaree : \"", nom, "\"\n", NULL);
      yyerror(message);
      free(message);
    }
}

void add_entete(returntype rettype, char *nom, arguments *args)
{
  symbole *s = lookup_decl(nom);
  /* S'il n'y a pas eu de prototype */
  if( s == NULL )
    {
      dico[sommet].content.func = malloc(sizeof(function*));
      current_func = sommet;
      if(sommet >= max)
	agrandir_dico();
      dico[sommet].nom = malloc(strlen(nom) + 1);
      strcpy(dico[sommet].nom, nom);
      dico[sommet].mtype = FONCTION;
      if(args != NULL)
	{ 
	  int nb_args = sizeof(args)/sizeof(arguments*);
	  dico[sommet].func_nb_args = nb_args;
	  cur_func_nb_args = nb_args;
	  int i;
	  dico[sommet].func_args = malloc(nb_args * sizeof(arguments*));
	  for(i = 0; i < nb_args; i++)
	    {
	      dico[sommet].func_args[i].nom = malloc(100 * sizeof(char));
	      strcpy(dico[sommet].func_args[i].nom, args[i].nom);
	      dico[sommet].func_args[i].type = args[i].type;
	    }
	}
      else
	dico[sommet].func_nb_args = 0;
      dico[sommet].func_visited = true;
      sommet++;
    }
  /* S'il y a eu un prototype ou si la fonction a déjà été parcourue */
  else
    {
      /* Verifier que le prototype correspond */
      if( ! s->func_visited )
	{
	  bool type_verif = true;
	  if(s->func_nb_args == 0 && args != NULL)
	    type_verif = false;
	  else if(s->func_nb_args == sizeof(args)/sizeof(arguments*))
	    {
	      int nb_args = sizeof(args)/sizeof(arguments*);
	      int i;
	      for(i = 0; i < nb_args; i++)
		if(s->func_args[i].type != args[i].type)
		  type_verif = false;
	    }
	  else
	    type_verif = false;
	  
	  if(type_verif)
	    {
	      /* Ajouter les noms des arguments à la signature */
	      int nb_args = sizeof(args)/sizeof(arguments*);
	      int i;
	      for(i = 0; i < nb_args; i++)
		strcpy(s->func_args[i].nom, args[i].nom);
	    }
	  else
	    {
	      char *message = concat("La signature de : \"", nom, "\" n'est pas la meme que celle de son prototype.\n", NULL);
	      yyerror(message);
	      free(message);
	    }
	}     
      else
	{
	  char *message = concat("Fonction deja declaree : ", nom, "\n", NULL);
	  yyerror(message);
	  free(message);
	}
    }
}

symbole * lookup_decl(char *nom){
  int i;
  for(i = sommet-1; i >= base; i--){
    if (!strcmp(dico[i].nom, nom))
      return (dico+i);
  }
  return NULL;
}

symbole * lookup_exec(char *nom){
  int i;
  for(i = sommet-1; i >= 0; i--){
    if (!strcmp(dico[i].nom, nom))
      return (dico+i);
  }
  char *message = concat("Identifiant non declare : ", nom, "\n", NULL);
  yyerror(message);
  free(message);
  return NULL;
}

void debut_local(){
  base = sommet;
}

void fin_local(){
  int i;
  for(i = sommet-1; i > base; i--){
    free(dico[i].nom);
    free(dico[i].var_adresse);
  }
  sommet = base;
  base = 0;
}
 
void display_symtab()
{
  char *buf;
  printf("Dictionnaire global :\n");
  int i;
  for(i = 0; i < base; i++)
    {
      if(dico[i].mtype == VARIABLE)
	{
	  printf("\tVariable \"%s\"\n\t\tValeur : %d\n\t\tAdresse : %s\n\\t\tStatique : %d\n", dico[i].nom, dico[i].var_val, dico[i].var_adresse, dico[i].var_static);
	}
      else
	{
	  printf("\tFonction \"%s\"\n\t\tType retour : %d\n\t\tNb args : %d\n\t\tVisitee : %d\n", dico[i].nom, dico[i].func_rettype, dico[i].func_nb_args, dico[i].func_visited);
	  int j;
	  for(j = 0; j < dico[i].func_nb_args; j++)
	    {
	      printf("\t\tArgument \"%s\"\n\t\t\tType : %d\n", dico[i].func_args[j].nom, dico[i].func_args[j].type );
	    }
	}
    }
  printf("Dictionnaire local :\n");
  for(i = base; i < sommet; i++)
    {
      if(dico[i].mtype == VARIABLE)
	{
	  printf("\tVariable \"%s\"\n\t\tValeur : %d\n\t\tAdresse : %s\n\t\tStatique : %d\n", dico[i].nom, dico[i].var_val, dico[i].var_adresse, dico[i].var_static);
	}
    }
}

